using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.CDS;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.Humans
{
    /// <summary>
    /// Provides functionality to grant a person(s) access to a study whom is not
    /// staffed to the study
    /// </summary>
    public partial class AddNonStudyStaff : BasePage
    {
        #region Instance Variables (Private)

        private ICachePolicy cachePolicy;
        private Hashtable pageCache;
        private ICachePolicy pageCachePolicy;
        private Protocol protocol;
        private int protocolId;
        private ProtocolProcess protocolProcess;
        private int protocolProcessId;
        private DataTable results;
        private DataTable selections;
        //This flag is used to decide whether or not the headers should be displayed
        //If the page is to be displayed as a popup, then the header section is made invisible
        private bool showAsPopUp;
        private int userAccessLevel;

        #endregion

        #region Constants

        private const string AnnunciatorTitle = "The following error(s) occurred...";
        private const int DefaultOrgSelection = 1;
        private const int OrganizationColumnIndex = 4;
        private const string PageCacheKey = "AddNonStaffPageKey_EBDBB6B3-9BB1-4c72-85B8-57B2DA542A99";
        private const string PageIndexKey = "NonStaffPageIndexKey_EBDBB6B3-9BB1-4c72-85B8-57B2DA542A99";
        private const string ProtocolIdKey = "ProtocolIDKey_EBDBB6B3-9BB1-4c72-85B8-57B2DA542A99";
        private const string SearchResultsKey = "NonStaffresultsKey_EBDBB6B3-9BB1-4c72-85B8-57B2DA542A99";
        private const string SelectionsKey = "NonStaffselectionsKey_EBDBB6B3-9BB1-4c72-85B8-57B2DA542A99";

        #endregion

        #region Properties (Private)

        /// <summary>
        /// Gets the protocol for which a nonstudystaff is being added.  If it's not already
        /// in the cache, it loads it up based on the protocolId passed to the page, and caches the object
        /// </summary>
        private Protocol Protocol
        {
            get
            {
                string cacheKey = Protocol.ProtocolKey;
                protocol = cachePolicy.GetCachedObject(cacheKey) as Protocol;

                if ((protocol == null) || (protocolId != protocol.Id))
                {
                    protocol = new Protocol(cachePolicy);
                    protocol.Load(DataAccess.GetConnectionString(), protocolId);
                    cachePolicy.Cache(cacheKey, protocol);
                }
                return protocol;
            }
        }

        /// <summary>
        /// Gets the protocol process for which a nonstudystaff is being added.  If it's not already
        /// in the cache, it loads it up based on the protocolProcessId passed to the page, and caches the 
        /// object
        /// </summary>
        private ProtocolProcess ProtocolProcess
        {
            get
            {
                protocolProcess = cachePolicy.GetCachedObject(ProtocolProcess.ProtocolProcessKey)
                    as ProtocolProcess;

                if ((protocolProcess == null) || (protocolProcessId != protocolProcess.Id))
                {
                    if (protocolProcessId > 0)
                    {
                        protocolProcess = ProtocolProcess.GetProtocolProcess(
                            DataAccess.GetConnectionString(), protocolProcessId, cachePolicy, null);
                        cachePolicy.Cache(ProtocolProcess.ProtocolProcessKey, protocolProcess);
                    }
                    else
                    {
                        protocolProcess = null;
                    }
                }
                return protocolProcess;
            }
        }

        /// <summary>
        /// The results of the search 
        /// </summary>
        private DataTable Results
        {
            get
            {
                if (results == null)
                {
                    results = pageCachePolicy.GetCachedObject(SearchResultsKey) as DataTable;
                }
                return results;
            }
            set
            {
                results = value;
                pageCachePolicy.Cache(SearchResultsKey, results);
            }
        }

        /// <summary>
        /// Table of people that the user has selected to staff to the protocol
        /// </summary>
        private DataTable Selections
        {
            get
            {
                selections = pageCachePolicy.GetCachedObject(SelectionsKey) as DataTable;
                if (selections == null)
                {
                    selections = results == null ? new DataTable() : results.Clone();
                    pageCachePolicy.Cache(SelectionsKey, selections);
                }
                return selections;
            }
        }

        #endregion

        /// <summary>
        /// On first load, the protocolId is retrieved from the cache, stored in ViewState, and the cache
        /// is flushed of all incoming data.  On subsequent loads, the protocolId is retrieved from 
        /// ViewState and the DataViews that the grids will get bound to are defined
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnPageLoad(object sender, EventArgs e)
        {
            try
            {
                breadCrumb.Add(
                    "Staff & Access",
                    Settings.GetKeyValue("SubModuleNavigation.Humans.AddStaffURL",
                        "AddNonStudyStaff.aspx"),
                    Settings.GetKeyValue("BreadCrumb.DetailPageLevel", 2));
                pageCache = pageCachePolicy.GetCachedObject(PageCacheKey) as Hashtable;
                annunciator.Message = string.Empty;


                if (!IsPostBack && postbackGuard.IsValid)
                {
                    /* Pull incoming data out of cache and store under the page's cache */
                    Hashtable incomingPageHash =
                        cachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;
                    if (incomingPageHash != null)
                    {
                        protocolId = Convert.ToInt32(incomingPageHash[Keys.ProtocolIdKey]);
                        protocolProcessId = Convert.ToInt32(incomingPageHash[Keys.ProtocolProcessIdKey]);
                        userAccessLevel = Convert.ToInt32(incomingPageHash[Keys.ProtocolAccessKey]);
                        if (incomingPageHash.ContainsKey(Keys.ShowAsPopUp))
                        {
                            showAsPopUp = Convert.ToBoolean(incomingPageHash[Keys.ShowAsPopUp]);
                        }

                        cachePolicy.UnCache(Keys.IncomingDataKey);
                    }

                    ViewState[ProtocolIdKey] = protocolId;

                    /* reset hashtable */
                    pageCache = new Hashtable();
                    pageCache[Keys.ProtocolIdKey] = protocolId;
                    /* Even though access is granted to the protocol and not the process, we need to hold 
					 * onto this value to pass back to the Staff & Access page */
                    pageCache[Keys.ProtocolProcessIdKey] = protocolProcessId;
                    pageCache[Keys.ProtocolAccessKey] = userAccessLevel;
                    pageCache[Keys.ShowAsPopUp] = showAsPopUp;
                    pageCachePolicy.Cache(PageCacheKey, pageCache);
                    topPager.Visible = bottomPager.Visible = false;
                    addUser.Enabled = false;
                }
                else
                {
                    protocolId = (int) pageCache[Keys.ProtocolIdKey];
                    protocolProcessId = (int) pageCache[Keys.ProtocolProcessIdKey];
                    showAsPopUp = (bool) pageCache[Keys.ShowAsPopUp];
                    addUser.Enabled = (searchResults.Items.Count > 0);
                }
                //if page is being shown as popup, then hide the header section
                headerSection.Visible = !showAsPopUp;
            }
            catch (Exception ex)
            {
                addUser.Enabled = false;
                DisplayExceptionReport(ex);
            }
            finally
            {
                protocolDetailHeader.ProtocolID = protocolId;
                //Set the humansubmodule Navigation links
                humansSubModuleNavigation.ProtocolProcess = ProtocolProcess;
                humansSubModuleNavigation.Protocol = Protocol;
            }
        }

        /// <summary>
        /// Moves the selected rows from the Results DataTable to the Selections
        /// DataTable and refreshes the contents of the grids
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnAddUser(object sender, ImageClickEventArgs e)
        {
            try
            {
                /* Determine which rows in the grid have been selected, and move them into the 
				 * Selections DataTable */
                if (postbackGuard.IsValid)
                {
                    DataRowCollection rows = Results.Rows;
                    int pageSize = searchResults.PageSize;

                    /* Determine the index of the last item displaying on the grid within the 
					 * shrunk set (10 items max) to iterate backwards and determine if the
					 * item is checked for adding to the Selections set.  If this is the last
					 * page of the grid determine the remainder after dividing the size of the 
					 * Results by the pageSize, and use that as the ending index to iterate from 
					 * (If the resultSet, however, is smaller than the pageSize, of course we
					 * should just use that) */
                    int resultSize = Results.Rows.Count;
                    int remainder = resultSize%pageSize;
                    int pageCount = PageCount;
                    int endIndex;
                    if (remainder == 0)
                    {
                        endIndex = pageSize - 1;
                    }
                    else if (resultSize < pageSize)
                    {
                        endIndex = remainder - 1;
                    }
                    else
                    {
                        if (CurrentPageIndex < (pageCount - 1))
                        {
                            endIndex = pageSize - 1;
                        }
                        else
                        {
                            endIndex = remainder - 1;
                        }
                    }
                    for (int i = endIndex; i >= 0; --i)
                    {
                        CheckBox cb = searchResults.Items[i].Controls[0].Controls[1] as CheckBox;
                        if (cb != null && cb.Checked)
                        {
                            DataRow row = rows[(CurrentPageIndex*pageSize) + i];
                            Selections.ImportRow(row);
                            rows.Remove(row);
                        }
                    }

                    searchResults.VirtualItemCount = rows.Count;

                    if ((CurrentPageIndex >= (pageCount - 1)) && (CurrentPageIndex > 0))
                    {
                        --CurrentPageIndex;
                    }

                    ManagePagers();
                    SetAndBindGrids();
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Displays an error message on the screen to the user with the exception, and all
        /// inner exception messages.
        /// </summary>
        /// <param name="ex">The exception to report on</param>
        private void DisplayExceptionReport(Exception ex)
        {
            annunciator.Title = AnnunciatorTitle;
            annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
        }

        /// <summary>
        /// Handles the search event by confirming that some search criteria has been selected
        /// (If this is not the case, a message is given to the user), then performs the search,
        /// binds the grid, and sets up the pagers.
        /// </summary>
        /// <param name="sender">sender of the search event</param>
        /// <param name="e">arguments of the event</param>
        private void OnSearch(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (postbackGuard.IsValid)
                {
                    /*if ((firstName.Text == string.Empty) && (lastName.Text == string.Empty) &&
						(username.Text == string.Empty) && 
						(organizationSelectors.SelectedOrganizationID == DefaultOrgSelection))*/

                    if ((firstName.Text == string.Empty) && (lastName.Text == string.Empty) &&
                        (username.Text == string.Empty))
                    {
                        annunciator.Message = "You must select some search criteria";
                        return;
                    }

                    PerformSearch();
                    CurrentPageIndex = 0;
                    int count = searchResults.VirtualItemCount = Results.Rows.Count;

                    SetAndBindGrids();

                    if (count == 0)
                    {
                        annunciator.Message = "The search has yielded no results or the person you are searching for has already been added to this record.";
                    }
                    else
                    {
                        ManagePagers();
                    }
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// On valid postbacks only, loads Results with data from the data repository
        /// based on search criteria entered by the user
        /// </summary>
        private void PerformSearch()
        {
            if (postbackGuard.IsValid)
            {
                Results = NonStudyStaff.GetNonStudyStaffWithoutAccess(
                    DataAccess.GetConnectionString(),
                    protocolId,
                    protocolProcessId,
                    lastName.Text,
                    firstName.Text,
                    username.Text,
                    //organizationSelectors.SelectedOrganizationID).Tables[0];
                    0).Tables[0];
            }

            /* Remove any records that have been selected on a previous search and moved to the other grid 
			 * since they could appear again in the Results set if the user initiated the same search */

            if (Selections.Rows.Count > 0)
            {
                foreach (DataRow selection in Selections.Rows)
                {
                    DataRow[] match = Results.Select(
                        String.Format("AdmPersonId = '{0}'", selection["AdmPersonId"]));
                    if (match.Length == 1)
                    {
                        Results.Rows.Remove(match[0]);
                    }
                }
            }
        }

        /// <summary>
        /// Iterates over the DataGrid with selected users, instantiating NonStaffPerson objects for each one
        /// and saving their state to the database
        /// </summary>
        private void PersistChanges()
        {
            if (postbackGuard.IsValid && Selections != null)
            {
                SqlConnection conn = new SqlConnection(DataAccess.GetConnectionString());
                conn.Open();
                SqlTransaction trans = conn.BeginTransaction();

                try
                {
                    DataRowCollection rows = Selections.Rows;
                    DataGridItemCollection items = selectedUsers.Items;

                    for (int i = 0, count = items.Count; i < count; ++i)
                    {
                        CheckBox remove = items[i].Cells[0].Controls[1] as CheckBox;
                        /* Make sure this row isn't checked for removal */
                        if (remove != null && !remove.Checked)
                        {
                            int defaultPermission = Protocol.ViewPermission;
                            NonStaffPerson person = new NonStaffPerson(cachePolicy, rows[i], defaultPermission);
                            person.ProtocolId = protocolId;
                            person.Save(trans);
                        }
                    }
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                    ExceptionReport.WriteToEventLog(
                        "AddNonStudyStaff.PersistChanges", ex, true, ExceptionReport.ReportType.Error);
                    annunciator.Message = "The changes you made failed to save";
                }
                finally
                {
                    if (conn.State != ConnectionState.Closed)
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// Formats the Fully Qualified Org Name (strips out domain if the org is not a domain)
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    /* Strip out "Partners >" from the beginning of the fully qualified org name, 
					 * if it exists */
                    TableCell org = e.Item.Cells[OrganizationColumnIndex];
                    org.Text = Organization.StripDomain(org.Text);
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handles the click event of the Save button by persisting the changes to the database, putting
        /// data relevant to the Staff & Access page in the cache, removing the key for the Selections from 
        /// the cache (so that the Selected Users grid is empty if the page is reloaded), and redirects
        /// to the Staff & Access page
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnSave(object sender, ImageClickEventArgs e)
        {
            try
            {
                PersistChanges();
                CacheOutgoingData(showAsPopUp);
                pageCachePolicy.UnCache(SelectionsKey);
                Response.Redirect(Settings.GetKeyValue(
                    "SubModuleNavigation.Humans.StaffAndAccessURL", "StaffAndAccess.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handles the cancel button click event by removing the key for the Selections from 
        /// the cache (so that the Selected Users grid is empty if the page is reloaded), and 
        /// redirecting to the StaffAndAccess page
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnCancel(object sender, ImageClickEventArgs e)
        {
            try
            {
                CacheOutgoingData(showAsPopUp);
                pageCachePolicy.UnCache(SelectionsKey);
                Response.Redirect(Settings.GetKeyValue(
                    "SubModuleNavigation.Humans.StaffAndAccessURL", "StaffAndAccess.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link before the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnBreadCrumbNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                humansSubModuleNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link before the header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                humansSubModuleNavigation.Reset();
                humansSubNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the selections in the search controls
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnClearSelection(object sender, ImageClickEventArgs e)
        {
            try
            {
                firstName.Text = lastName.Text = username.Text = string.Empty;
                //organizationSelectors.SelectedOrganizationID = DefaultOrgSelection; 
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Constructs and caches a hashtable of data for use by the page to which nagivation leads
        /// </summary>
        private void OnNavigate()
        {
            try
            {
                CacheOutgoingData(false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        #region Web Form Designer generated code

        /// <summary>
        /// Initializes the page and sets up the caching policies
        /// </summary>
        /// <param name="e">arguments from the event</param>
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);

            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.header.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.humansSubModuleNavigation.Navigate += new PHSRAG.Insight21.InsightWebControls.HumansSubModuleNavigation.NavigateEventHandler(this.OnNavigate);
            this.breadCrumb.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnBreadCrumbNavigate);
            this.search.Click += new ImageClickEventHandler(OnSearch);
            this.clearSelection.Click += new ImageClickEventHandler(OnClearSelection);
            this.topPager.FirstPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnFirstPage);
            this.topPager.PreviousPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnPreviousPage);
            this.topPager.NextPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnNextPage);
            this.topPager.LastPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnLastPage);
            this.searchResults.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnItemDataBound);
            this.bottomPager.FirstPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnFirstPage);
            this.bottomPager.PreviousPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnPreviousPage);
            this.bottomPager.NextPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnNextPage);
            this.bottomPager.LastPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnLastPage);
            this.addUser.Click += new ImageClickEventHandler(OnAddUser);
            this.selectedUsers.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnItemDataBound);
            this.cancel.Click += new ImageClickEventHandler(OnCancel);
            this.save.Click += new ImageClickEventHandler(OnSave);
            this.Load += new System.EventHandler(this.OnPageLoad);
        }

        #endregion

        #region Pager Event Handlers and Private Helpers

        /// <summary>
        /// Get/Set the current page within the datagrid for display.
        /// </summary>
        private int CurrentPageIndex
        {
            get
            {
                object pageIndex = pageCache[PageIndexKey];
                if (pageIndex == null)
                {
                    return 0;
                }
                return Convert.ToInt32(pageIndex);
            }
            set
            {
                pageCache[PageIndexKey] = value;
                searchResults.CurrentPageIndex = value;
                pageCachePolicy.Cache(PageCacheKey, pageCache);
            }
        }

        /// <summary>
        /// The number of pages in the grid
        /// </summary>
        private int PageCount
        {
            get
            {
                int recordCount = Results.Rows.Count;
                return (recordCount/searchResults.PageSize) +
                    (((recordCount%searchResults.PageSize) == 0) ? 0 : 1);
            }
        }

        /// <summary>
        /// Occurs when the NexttPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the next page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnNextPage(object sender, CommandEventArgs e)
        {
            try
            {
                ++CurrentPageIndex;
                SetAndBindGrids();
                ManagePagers();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Occurs when the PreviousPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the previous page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnPreviousPage(object sender, CommandEventArgs e)
        {
            try
            {
                --CurrentPageIndex;
                SetAndBindGrids();
                ManagePagers();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Occurs when the FirstPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the first page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnFirstPage(object sender, CommandEventArgs e)
        {
            try
            {
                CurrentPageIndex = 0;
                SetAndBindGrids();
                ManagePagers();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Occurs when the LastPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the last page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnLastPage(object sender, CommandEventArgs e)
        {
            try
            {
                CurrentPageIndex = topPager.PageCount - 1;
                SetAndBindGrids();
                ManagePagers();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Determine first and last number of the displaying records, page count, and record count,
        /// and sets these values on the pagers and on the grid; Enables/disables pager links to other pages 
        /// within the grid
        /// </summary>
        private void ManagePagers()
        {
            int recordCount = topPager.RecordCount = bottomPager.RecordCount = Results.Rows.Count;

            int currentPageIndex = CurrentPageIndex;
            searchResults.CurrentPageIndex = currentPageIndex;

            int pageSize = searchResults.PageSize;
            int startIndex = currentPageIndex*pageSize;
            bottomPager.FirstRecord = topPager.FirstRecord = startIndex + 1;

            int lastRecord = results.Rows.Count;
            bottomPager.LastRecord = topPager.LastRecord = Math.Min(startIndex + pageSize, lastRecord);

            bottomPager.CurrentPage = topPager.CurrentPage = currentPageIndex + 1;

            bottomPager.PageCount = topPager.PageCount =
                (recordCount/searchResults.PageSize) +
                    (((recordCount%searchResults.PageSize) == 0) ? 0 : 1);

            bottomPager.EnableFirstPage = topPager.EnableFirstPage =
                bottomPager.EnablePreviousPage = topPager.EnablePreviousPage =
                    (searchResults.CurrentPageIndex != 0);

            bottomPager.EnableLastPage = topPager.EnableLastPage =
                bottomPager.EnableNextPage = topPager.EnableNextPage =
                    (searchResults.CurrentPageIndex != (topPager.PageCount - 1));
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Determines the subset of the searchResults to be used as the dataSource for the results
        /// grid and binds each grid to their respective dataSources; Also sets pager visibility based
        /// on a non-zero size resultSet
        /// </summary>
        private void SetAndBindGrids()
        {
            DataTable pagedResults = Results.Clone();
            int pageSize = searchResults.PageSize;
            int startIndex = CurrentPageIndex*pageSize;

            DataRowCollection rows = Results.Rows;

            for (int m = startIndex, endIndex = Math.Min(Results.Rows.Count, startIndex + pageSize);
                m < endIndex; ++m)
            {
                pagedResults.ImportRow(rows[m]);
            }

            topPager.Visible = bottomPager.Visible = addUser.Enabled = (rows.Count > 0);
            searchResults.DataSource = pagedResults;
            searchResults.DataBind();
            selectedUsers.DataSource = Selections;
            selectedUsers.DataBind();
        }

        /// <summary>
        /// Stores the data relevant to the destination page in a hashtable and caches it under the 
        /// IncomingData key
        /// </summary>
        private void CacheOutgoingData(bool showTargetAsPopUp)
        {
            Hashtable outgoingData = new Hashtable();
            outgoingData.Add(Keys.ProtocolIdKey, protocolId);
            outgoingData.Add(Keys.ProtocolProcessIdKey, protocolProcessId);
            outgoingData.Add(Keys.ProtocolAccessKey, pageCache[Keys.ProtocolAccessKey]);
            outgoingData.Add(Keys.ShowAsPopUp, showTargetAsPopUp);
            outgoingData.Add(Keys.ProtocolReloadNonStaffKey, true);
            pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
        }

        #endregion
    }
}